//
//  JsPixelbufferManager.m
//  JsoUtilitySdk
//
//  Created by Gikki Ares on 2021/11/8.
//

#import "Js_PixelBufferManager.h"

@implementation Js_PixelBufferManager

+ (instancetype)sharedInstance {
	static Js_PixelBufferManager * _sharedInstance;
	static dispatch_once_t onceToken;
	dispatch_once(&onceToken, ^{
		_sharedInstance = [Js_PixelBufferManager new];
	});
	return _sharedInstance;
}



+ (UIImage *)imageFromRgbaPixelBuffer:(CVPixelBufferRef)pixelBuffer {
	CGImageRef cgimage = [self cgimageFromRgbaPixelBuffer:pixelBuffer];
	UIImage * image = [UIImage imageWithCGImage:cgimage];
	return image;
}

+ (CGImageRef)cgimageFromRgbaPixelBuffer:(CVPixelBufferRef)pixelBuffer {
		//获取PixelBuffer的相关信息.
	uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
	size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
	size_t width = CVPixelBufferGetWidth(pixelBuffer);
	size_t height = CVPixelBufferGetHeight(pixelBuffer);
	
	
		//堆中创建RGB颜色空间对象,不用时需要释放.
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
		//堆中创建上下文对象,不用时需要释放.
	CGContextRef context = CGBitmapContextCreate(baseAddress,width, height,8,bytesPerRow,colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
	
		//	CGContextRef newContext = CGBitmapContextCreate(baseAddress,width, height,8,bytesPerRow,colorSpace,kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);
		//创建一个CGImage对象,包含了pixelbuffer图像数据的拷贝,需要在后面不用时释放掉.
	CGImageRef cgimage = CGBitmapContextCreateImage(context);
		//释放颜色空间和上下文
	CGContextRelease(context);
	CGColorSpaceRelease(colorSpace);
	return cgimage;
}


#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
+ (void)displayImageInfo:(CGImageRef)cgimage {
	size_t width  = CGImageGetWidth(cgimage);
	size_t height = CGImageGetHeight(cgimage);
	
	size_t bpr = CGImageGetBytesPerRow(cgimage);
	size_t bpp = CGImageGetBitsPerPixel(cgimage);
	size_t bpc = CGImageGetBitsPerComponent(cgimage);
	size_t bytes_per_pixel = bpp / bpc;
	
	CGBitmapInfo info = CGImageGetBitmapInfo(cgimage);
	CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(cgimage);
	NSLog(
		  @"\n"
		  "===== %@ =====\n"
		  "CGImageGetHeight: %d\n"
		  "CGImageGetWidth:  %d\n"
		  "CGImageGetColorSpace: %@\n"
		  "CGImageGetBitsPerPixel:     %d\n"
		  "CGImageGetBitsPerComponent: %d\n"
		  "CGImageGetBytesPerRow:      %d\n"
		  "CGImageGetBitmapInfo: 0x%.8X\n"
		  "  kCGBitmapAlphaInfoMask     = %s\n"
		  "  kCGBitmapFloatComponents   = %s\n"
		  "  kCGBitmapByteOrderMask     = %s\n"
		  "  kCGBitmapByteOrderDefault  = %s\n"
		  "  kCGBitmapByteOrder16Little = %s\n"
		  "  kCGBitmapByteOrder32Little = %s\n"
		  "  kCGBitmapByteOrder16Big    = %s\n"
		  "  kCGBitmapByteOrder32Big    = %s\n"
		  "  AlphaInfo                  = %@\n",
		  @"位图信息",
		  (int)width,
		  (int)height,
		  CGImageGetColorSpace(cgimage),
		  (int)bpp,
		  (int)bpc,
		  (int)bpr,
		  (unsigned)info,
		  (info & kCGBitmapAlphaInfoMask)     ? "YES" : "NO",
		  (info & kCGBitmapFloatComponents)   ? "YES" : "NO",
		  (info & kCGBitmapByteOrderMask)     ? "YES" : "NO",
		  (info & kCGBitmapByteOrderDefault)  ? "YES" : "NO",
		  (info & kCGBitmapByteOrder16Little) ? "YES" : "NO",
		  (info & kCGBitmapByteOrder32Little) ? "YES" : "NO",
		  (info & kCGBitmapByteOrder16Big)    ? "YES" : "NO",
		  (info & kCGBitmapByteOrder32Big)    ? "YES" : "NO",
		  //AlphaInfo
		  [self infoForAlphaInfo:alphaInfo]
		  
		  );
	return;
	CGDataProviderRef provider = CGImageGetDataProvider(cgimage);
	NSData* data = (id)CFBridgingRelease(CGDataProviderCopyData(provider));
	const uint8_t* bytes = [data bytes];
	
	printf("Pixel Data:\n");
	for(size_t row = 0; row < height; row++)
	{
		for(size_t col = 0; col < width; col++)
		{
			const uint8_t* pixel =
			&bytes[row * bpr + col * bytes_per_pixel];
			
			printf("(");
			for(size_t x = 0; x < bytes_per_pixel; x++)
			{
				printf("%.2X", pixel[x]);
				if( x < bytes_per_pixel - 1 )
					printf(",");
			}
			
			printf(")");
			if( col < width - 1 )
				printf(", ");
		}
		
		printf("\n");
	}
}
#pragma clang diagnostic pop

+ (NSString *)infoForAlphaInfo:(CGImageAlphaInfo)alphaInfo {
	NSString * info=nil;
	switch (alphaInfo) {
		case kCGImageAlphaNone:
			info= @"kCGImageAlphaNone,无alpha通道";
			break;
		case kCGImageAlphaPremultipliedLast:
			info= @"kCGImageAlphaPremultipliedLast,RGBA,颜色通道在大地址,并且已经乘进去了";
			break;
		case kCGImageAlphaPremultipliedFirst:
			info= @"kCGImageAlphaPremultipliedFirst,ARGB,颜色通道在小地址,并且已经乘进去了";
			break;
		case kCGImageAlphaLast:
			info= @"kCGImageAlphaLast,RGBA,颜色通道在大地址,没有乘进去";
			break;
		case kCGImageAlphaFirst:              /* For example, non-premultiplied ARGB */
			info= @"kCGImageAlphaFirst,ARGB,颜色通道在小地址,没有乘进去";
			break;
		case kCGImageAlphaNoneSkipLast:      /* For example, RBGX.????RGBX!!! */
			info= @"kCGImageAlphaNoneSkipLast,RBGX,颜色通道在大地址";
			break;
		case kCGImageAlphaNoneSkipFirst:      /* For example, XRGB. */
			info= @"kCGImageAlphaNoneSkipFirst,XRGB,颜色通道在小地址";
			break;
		case kCGImageAlphaOnly:
			info= @"kCGImageAlphaOnly,A,仅包含alpha值";
			break;
	}
	NSString * result = [NSString stringWithFormat:@"%d:%@",alphaInfo,info];
	return result;
}
+ (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)cgimage {
	NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
							 @(YES), kCVPixelBufferCGImageCompatibilityKey,
							 @(YES), kCVPixelBufferCGBitmapContextCompatibilityKey,
							 @(YES), kCVPixelBufferOpenGLESCompatibilityKey,
							 nil];
	
	
	CVPixelBufferRef pxbuffer = NULL;
	
	CGFloat frameWidth = CGImageGetWidth(cgimage);
	CGFloat frameHeight = CGImageGetHeight(cgimage);
	
	CVReturn status = CVPixelBufferCreate(kCFAllocatorDefault,
										  frameWidth,
										  frameHeight,
										  kCVPixelFormatType_32ARGB,
										  (__bridge CFDictionaryRef) options,
										  &pxbuffer);
	
	NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);
	
	CVPixelBufferLockBaseAddress(pxbuffer, 0);
	void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
	NSParameterAssert(pxdata != NULL);
	
	CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
	
	CGContextRef context = CGBitmapContextCreate(pxdata,
												 frameWidth,
												 frameHeight,
												 8,
												 CVPixelBufferGetBytesPerRow(pxbuffer),
												 rgbColorSpace,
												 (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
	NSParameterAssert(context);
	CGContextConcatCTM(context, CGAffineTransformIdentity);
	CGContextDrawImage(context, CGRectMake(0,
										   0,
										   frameWidth,
										   frameHeight),
					   cgimage);
	CGColorSpaceRelease(rgbColorSpace);
	CGContextRelease(context);
	
	CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
	
	return pxbuffer;
	
}

+ (CVPixelBufferRef)pixelBufferFromImage:(UIImage *)image {
	CGImageRef cgimage = image.CGImage;
	return [self pixelBufferFromCGImage:cgimage];
}

	//	kCVPixelBufferOpenGLCompatibilityKey
	//	kCVPixelBufferIOSurfacePropertiesKey属性创建
- (CVPixelBufferRef)pixelBufferFromCGImage2:(CGImageRef)cgimage {
	CGFloat frameWidth = CGImageGetWidth(cgimage);
	CGFloat frameHeight = CGImageGetHeight(cgimage);
	
	
	CFDictionaryRef empty = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
	
	CFMutableDictionaryRef attrs = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
	CFDictionarySetValue(attrs, kCVPixelBufferIOSurfacePropertiesKey, empty);
	
		//创建具有kCVPixelBufferIOSurfacePropertiesKey属性的CVPixelBufferRef实例renderTarget
	CVPixelBufferRef renderTarget = NULL;
	CVReturn err = CVPixelBufferCreate(kCFAllocatorDefault, frameWidth, frameHeight, kCVPixelFormatType_32BGRA, attrs, &renderTarget);
	if(err) {
		
	}
	
	return renderTarget;
	
}

/**
 CMSampleBuffer中包含了图片的格式等信息,要创建和该buffer内容一致的信息才可以成功;
 */
+ (CGImageRef)cgimageFormSampleBuffer:(CMSampleBufferRef)sb {
	CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sb);
	CVPixelBufferLockBaseAddress(pixelBuffer,0);
	uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
	size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
		//1134
	size_t width = CVPixelBufferGetWidth(pixelBuffer);
		//640
	size_t height = CVPixelBufferGetHeight(pixelBuffer);
		//309
	CFTypeID typeId = CVPixelBufferGetTypeID();
	NSLog(@"Type id is %zu",typeId);
		//34323066,875704422
	unsigned long formatType = CVPixelBufferGetPixelFormatType(pixelBuffer);
	NSLog(@"Format type  is %zu",formatType);
	
	
	
	BOOL isPlannar = CVPixelBufferIsPlanar(pixelBuffer);
	if(isPlannar) {
		NSLog(@"平面的");
		size_t planeCount = CVPixelBufferGetPlaneCount(pixelBuffer);
		NSLog(@"一共有%zu个平面",planeCount);
			//		第0个平面,width is:1134,height is:1134
			//		第1个平面,width is:567,height is:567
		
		for(int i = 0 ;i<planeCount;i++) {
			size_t width = CVPixelBufferGetWidthOfPlane(pixelBuffer,i);
			size_t height = CVPixelBufferGetWidthOfPlane(pixelBuffer,i);
			NSLog(@"第%d个平面,width is:%zu,height is:%zu",i,width,height);
		}
	}
	else {
		NSLog(@"不是平面的");
	}
	
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
	CGContextRef newContext = CGBitmapContextCreate(baseAddress,width, height,8,bytesPerRow,colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
	CGImageRef cgimage = CGBitmapContextCreateImage(newContext);
	return cgimage;
}

+ (void)showPixelBufferInfo:(CVPixelBufferRef)pb {
		//		CFTypeRef colorAttachments = CVBufferGetAttachment(pb, kCVImageBufferYCbCrMatrixKey, NULL);
}


	//外部传来的pixelBuffer由外部负责释放掉.
	//内部函数只保证内部范围内的对象释放.
/**
 此PixelBuffer必须是RGBA格式的,才能创建image成功.
 pixcelBuffer有自己的格式,必须创建对应格式的image.
 */
+ (CGImageRef)cgimageFormPixelBuffer:(CVPixelBufferRef)pPixelBuffer {
		//获取PixelBuffer的相关信息.
	uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(pPixelBuffer);
	size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pPixelBuffer);
	size_t width = CVPixelBufferGetWidth(pPixelBuffer);
	size_t height = CVPixelBufferGetHeight(pPixelBuffer);
	
	
		//堆中创建RGB颜色空间对象,不用时需要释放.
	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
		//堆中创建上下文对象,不用时需要释放.
	CGContextRef context = CGBitmapContextCreate(baseAddress,width, height,8,bytesPerRow,colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
	
		//	CGContextRef newContext = CGBitmapContextCreate(baseAddress,width, height,8,bytesPerRow,colorSpace,kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast);
		//创建一个CGImage对象,包含了pixelbuffer图像数据的拷贝,需要在后面不用时释放掉.
	CGImageRef cgimage = CGBitmapContextCreateImage(context);
		//释放颜色空间和上下文
	CGContextRelease(context);
	CGColorSpaceRelease(colorSpace);
	return cgimage;
}


	//图片的裸数据
+ (GLvoid*)rawImageDataOfCGImage:(CGImageRef)cgimage {
		//    Method1,栈变量,会自动释放,不需要释放
	
	CGDataProviderRef dataProvider = CGImageGetDataProvider(cgimage);
	
		//这个copydata,并没有copy整个数据吧...???
	CFDataRef  dataFromImageDataProvider = CGDataProviderCopyData(dataProvider);
	GLubyte *  imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
		//这样释放的是整个图片.
		//    CGDataProviderRelease(dataProvider);
	return imageData;
	
		//    //Method2
		//    // 2 读取图片的大小
		//      size_t width = CGImageGetWidth(cgimage);
		//      size_t height = CGImageGetHeight(cgimage);
		//      //CPU的缓存区
		//      GLubyte * imageData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte)); //rgba共4个byte
		//      //CPU的位图上下文,包含缓存区信息的一个结构体
		//      CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width*4,
		//                                                         CGImageGetColorSpace(cgimage), kCGImageAlphaPremultipliedLast);
		//
		//      // 3在CGContextRef上绘图,将数据绘制到上下文指定的缓存区.
		//      CGContextDrawImage(context, CGRectMake(0, 0, width, height), cgimage);
		//      // 释放掉上下文结构体,但是缓存区还在.
		//      CGContextRelease(context);
		//    return imageData;
}




/**
 CMSampleBuffer中包含了图片的格式等信息,要创建和该buffer内容一致的信息才可以成功;
 */
+ (void)checkCVPixelBuffeInfo:(CVPixelBufferRef)pixelBuffer {
	CVPixelBufferLockBaseAddress(pixelBuffer,0);
	uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(pixelBuffer);
	size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
		//1134
	size_t width = CVPixelBufferGetWidth(pixelBuffer);
		//640
	size_t height = CVPixelBufferGetHeight(pixelBuffer);
	
	size_t size = CVPixelBufferGetDataSize(pixelBuffer);
	
	
	NSLog(@"PixelBuffer baseAddress is %p, width is %zu, height is %zu,bytesPerRow is %zu,dataSize is %zu",baseAddress,width,height,bytesPerRow,size);
	
		//309是CVPixelBuffer类型的类型id
	CFTypeID typeId = CVPixelBufferGetTypeID();
	NSLog(@"Type id is %lu",typeId);
		//相机支持下面三种:
		// 875704438??
		//875704422-->34323066-->kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
		//1111970369-->42475241-->kCVPixelFormatType_32BGRA
	unsigned long formatType = CVPixelBufferGetPixelFormatType(pixelBuffer);
	NSLog(@"Format type  is %zu",formatType);
	
	
	BOOL isPlannar = CVPixelBufferIsPlanar(pixelBuffer);
	if(isPlannar) {
		NSLog(@"平面的");
		size_t planeCount = CVPixelBufferGetPlaneCount(pixelBuffer);
		NSLog(@"一共有%zu个平面",planeCount);
			//		第0个平面,width is:1134,height is:1134
			//		第1个平面,width is:567,height is:567
		
		for(int i = 0 ;i<planeCount;i++) {
			size_t width = CVPixelBufferGetWidthOfPlane(pixelBuffer,i);
			size_t height = CVPixelBufferGetHeightOfPlane(pixelBuffer,i);
			uint8_t * baseAddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer,i);
			size_t size = CVPixelBufferGetBytesPerRowOfPlane(pixelBuffer,i);
			NSLog(@"第%d个平面,baseAddress is: %p, width is:%zu,height is:%zu,size is:%zu",i,baseAddress,width,height,size);
		}
	}
	else {
		NSLog(@"不是平面的");
		
	}
	return;
	
		//	CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
		//	CGContextRef newContext = CGBitmapContextCreate(baseAddress,width, height,8,bytesPerRow,colorSpace,kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
		//	CGImageRef cgimage = CGBitmapContextCreateImage(newContext);
		//	return cgimage;
}


@end
